package com.ssy.lingxi.marketing.serviceimpl.component.coupon;

import com.ssy.lingxi.common.constant.Constants;
import com.ssy.lingxi.common.constant.marketing.BelongTypeEnum;
import com.ssy.lingxi.common.model.bo.MemberAndRoleIdBO;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.marketing.entity.coupon.MerchantCouponDO;
import com.ssy.lingxi.marketing.entity.coupon.MerchantCouponDetailDO;
import com.ssy.lingxi.marketing.entity.coupon.PlatformCouponDO;
import com.ssy.lingxi.marketing.entity.coupon.PlatformCouponDetailDO;
import com.ssy.lingxi.marketing.model.bo.AtCanReceiveSuitableMemberBO;
import com.ssy.lingxi.marketing.model.bo.PfCanReceiveSuitableMemberBO;
import com.ssy.lingxi.marketing.model.constant.*;
import com.ssy.lingxi.marketing.model.dto.CouponDetailExpireDTO;
import com.ssy.lingxi.marketing.model.vo.coupon.request.MerchantCouponGrantMemberRequest;
import com.ssy.lingxi.marketing.model.vo.coupon.request.PlatformCouponGrantMemberRequest;
import com.ssy.lingxi.marketing.repository.MerchantCouponDetailRepository;
import com.ssy.lingxi.marketing.repository.PlatformCouponDetailRepository;
import com.ssy.lingxi.marketing.serviceimpl.component.SuitableMemberInfoComponent;
import com.ssy.lingxi.member.merchant.api.model.vo.inner.response.AtSubMemberSuitableMemberVO;
import com.ssy.lingxi.member.merchant.api.model.vo.inner.response.PfSubMemberSuitableMemberVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 优惠券领取组件
 * @author yzc
 * @version 2.0.0
 * @date 2021/9/17
 */
@Slf4j
@Component
public class CouponReceiveComponent {

    @Resource
    private MerchantCouponDetailRepository merchantCouponDetailRepository;
    @Resource
    private PlatformCouponDetailRepository platformCouponDetailRepository;
    @Resource
    private CouponReceiveCheckRuleComponent couponReceiveCheckRuleComponent;
    @Resource
    private SuitableMemberInfoComponent suitableMemberInfoComponent;
    @Resource
    private CouponCacheComponent couponCacheComponent;
    @Resource
    private CouponDetailExpireComponent couponDetailExpireComponent;

    /**
     * 自动领取平台优惠券
     * @param loginUser 登录用户信息
     * @param shopId 商城id
     * @param platformCouponDOList 平台优惠券
     * @return 返回结果
     */
    public List<PlatformCouponDetailDO> autoReceivePlatformCoupon(UserLoginCacheDTO loginUser, Long shopId, List<PlatformCouponDO> platformCouponDOList) {
        // 查询会员关系(需会员登录)
        PfSubMemberSuitableMemberVO subMemberSuitableMemberVO = null;
        subMemberSuitableMemberVO = suitableMemberInfoComponent.getPlatformSubMemberSuitableMember(loginUser.getMemberId(), loginUser.getMemberRoleId());
        if (Objects.isNull(subMemberSuitableMemberVO)) {
            return Collections.emptyList();
        }

        List<PlatformCouponDetailDO> saveCouponDetailList = new ArrayList<>();
        for (PlatformCouponDO platformCouponDO : platformCouponDOList) {
            // 判断是否可领取
            PfCanReceiveSuitableMemberBO pfCanReceiveSuitableMemberBO = couponReceiveCheckRuleComponent.baseCheckPlatformCanReceiveComplete(loginUser, platformCouponDO, shopId, subMemberSuitableMemberVO);
            if (CanReceiveEnum.noReceiveList().contains(pfCanReceiveSuitableMemberBO.getCanReceive())) {
                continue;
            }

            // 优惠券发券数量
            Integer value = couponCacheComponent.incrCouponObtainQuantity(BelongTypeEnum.PLATFORM, platformCouponDO.getId(), platformCouponDO.getQuantity());
            if (Objects.isNull(value)) {
                continue;
            }

            // 保存领取明细
            PlatformCouponDetailDO platformCouponDetailDO = new PlatformCouponDetailDO();
            platformCouponDetailDO.setCoupon(platformCouponDO);
            platformCouponDetailDO.setStatus(PlatformCouponDetailStatusEnum.RECEIVE.getCode());
            platformCouponDetailDO.setMemberId(platformCouponDO.getMemberId());
            platformCouponDetailDO.setRoleId(platformCouponDO.getRoleId());
            platformCouponDetailDO.setSubMemberId(loginUser.getMemberId());
            platformCouponDetailDO.setSubRoleId(loginUser.getMemberRoleId());
            platformCouponDetailDO.setSubMemberName(loginUser.getCompany());
            platformCouponDetailDO.setSuitableMemberType(pfCanReceiveSuitableMemberBO.getSuitableMember().getCode());
            if (PlatformCouponEffectiveTypeEnum.FIXED.getCode().equals(platformCouponDO.getEffectiveType())) {
                // 固定有效时间
                platformCouponDetailDO.setValidTimeStart(platformCouponDO.getEffectiveTimeStart());
                platformCouponDetailDO.setValidTimeEnd(platformCouponDO.getEffectiveTimeEnd());
            } else if (PlatformCouponEffectiveTypeEnum.SELF.getCode().equals(platformCouponDO.getEffectiveType())) {
                // 自领取开始, 天 -> 毫秒
                Long millisSecond = Optional.ofNullable(platformCouponDO.getInvalidDay()).map(day -> day * Constants.DAY_TO_MILLISECONDS).orElse(0L);
                platformCouponDetailDO.setValidTimeStart(System.currentTimeMillis());
                platformCouponDetailDO.setValidTimeEnd(System.currentTimeMillis() + millisSecond);
            }
            platformCouponDetailDO.setCreateTime(System.currentTimeMillis());
            saveCouponDetailList.add(platformCouponDetailDO);
        }

        // 保存数据
        platformCouponDetailRepository.saveAll(saveCouponDetailList);

        // 生成券码
        for (PlatformCouponDetailDO platformCouponDetailDO : saveCouponDetailList) {
            platformCouponDetailDO.setCode(couponCacheComponent.generatePlatformCouponCode(platformCouponDetailDO.getId()));
        }
        platformCouponDetailRepository.saveAll(saveCouponDetailList);

        // 优惠券过期
        for (PlatformCouponDetailDO platformCouponDetailDO : saveCouponDetailList) {
            couponDetailExpireComponent.sendMqMsgCouponDetailExpire(this.createPfCouponDetailDTO(platformCouponDetailDO));
        }

        return saveCouponDetailList;
    }

    /**
     * 自动领取商家优惠券
     * @param loginUser 登录用户信息
     * @param shopId 商城id
     * @param merchantCouponDOList 商家优惠券
     * @return 返回结果
     */
    public List<MerchantCouponDetailDO> autoReceiveMerchantCoupon(UserLoginCacheDTO loginUser, Long shopId, List<MerchantCouponDO> merchantCouponDOList) {
        // 查询会员关系
        List<AtSubMemberSuitableMemberVO> subMemberSuitableMemberVOList = null;
        subMemberSuitableMemberVOList = suitableMemberInfoComponent.listAbilitySubMemberSuitableMember(loginUser.getMemberId(), loginUser.getMemberRoleId(),
                merchantCouponDOList.stream().map(e -> new MemberAndRoleIdBO(e.getMemberId(), e.getRoleId())).collect(Collectors.toList()));
        if (CollectionUtils.isEmpty(subMemberSuitableMemberVOList)) {
            return Collections.emptyList();
        }

        List<MerchantCouponDetailDO> saveCouponDetailList = new ArrayList<>();
        for (MerchantCouponDO merchantCouponDO : merchantCouponDOList) {
            AtCanReceiveSuitableMemberBO atCanReceiveSuitableMemberBO = couponReceiveCheckRuleComponent.baseCheckMerchantCanReceiveComplete(loginUser, merchantCouponDO, shopId, subMemberSuitableMemberVOList);
            if (CanReceiveEnum.noReceiveList().contains(atCanReceiveSuitableMemberBO.getCanReceive())) {
                continue;
            }

            Integer value = couponCacheComponent.incrCouponObtainQuantity(BelongTypeEnum.MERCHANT, merchantCouponDO.getId(), merchantCouponDO.getQuantity());
            if (Objects.isNull(value)) {
                continue;
            }

            MerchantCouponDetailDO merchantCouponDetailDO = new MerchantCouponDetailDO();
            merchantCouponDetailDO.setCoupon(merchantCouponDO);
            merchantCouponDetailDO.setStatus(MerchantCouponDetailStatusEnum.RECEIVE.getCode());
            merchantCouponDetailDO.setMemberId(merchantCouponDO.getMemberId());
            merchantCouponDetailDO.setRoleId(merchantCouponDO.getRoleId());
            merchantCouponDetailDO.setSubMemberId(loginUser.getMemberId());
            merchantCouponDetailDO.setSubRoleId(loginUser.getMemberRoleId());
            merchantCouponDetailDO.setSubMemberName(loginUser.getCompany());
            merchantCouponDetailDO.setSuitableMemberType(atCanReceiveSuitableMemberBO.getSuitableMember().getCode());
            if (MerchantCouponEffectiveTypeEnum.FIXED.getCode().equals(merchantCouponDO.getEffectiveType())) {
                // 固定有效时间
                merchantCouponDetailDO.setValidTimeStart(merchantCouponDO.getEffectiveTimeStart());
                merchantCouponDetailDO.setValidTimeEnd(merchantCouponDO.getEffectiveTimeEnd());
            } else if (MerchantCouponEffectiveTypeEnum.SELF.getCode().equals(merchantCouponDO.getEffectiveType())) {
                // 自领取开始, 天 -> 毫秒
                Long millisSecond = Optional.ofNullable(merchantCouponDO.getInvalidDay()).map(day -> day * Constants.DAY_TO_MILLISECONDS).orElse(0L);
                merchantCouponDetailDO.setValidTimeStart(System.currentTimeMillis());
                merchantCouponDetailDO.setValidTimeEnd(System.currentTimeMillis() + millisSecond);
            }
            merchantCouponDetailDO.setCreateTime(System.currentTimeMillis());

            saveCouponDetailList.add(merchantCouponDetailDO);
        }
        // 保存数据
        merchantCouponDetailRepository.saveAll(saveCouponDetailList);
        // 生成券码
        for (MerchantCouponDetailDO merchantCouponDetailDO : saveCouponDetailList) {
            merchantCouponDetailDO.setCode(couponCacheComponent.generateMerchantCouponCode(merchantCouponDetailDO.getId()));
        }
        merchantCouponDetailRepository.saveAll(saveCouponDetailList);

        // 优惠券过期
        for (MerchantCouponDetailDO merchantCouponDetailDO : saveCouponDetailList) {
            couponDetailExpireComponent.sendMqMsgCouponDetailExpire(this.createMcCouponDetailDTO(merchantCouponDetailDO));
        }

        return saveCouponDetailList;
    }

    /**
     * 领取平台优惠券
     * @param loginUser 登录用户信息
     * @param shopId 商城id
     * @param platformCouponDO 平台优惠券
     * @return 返回结果
     */
    public Wrapper<CanReceiveEnum> receivePlatformCoupon(UserLoginCacheDTO loginUser, Long shopId, PlatformCouponDO platformCouponDO) {
        // 查询会员关系(需会员登录)
        PfSubMemberSuitableMemberVO subMemberSuitableMemberVO = null;
        subMemberSuitableMemberVO = suitableMemberInfoComponent.getPlatformSubMemberSuitableMember(loginUser.getMemberId(), loginUser.getMemberRoleId());
        if (Objects.isNull(subMemberSuitableMemberVO)) {
            return Wrapper.fail(ResponseCode.MARKETING_QUERY_MEMBER_RELATION);
        }

        // 判断是否可领取
        PfCanReceiveSuitableMemberBO pfCanReceiveSuitableMemberBO = couponReceiveCheckRuleComponent.baseCheckPlatformCanReceiveComplete(loginUser, platformCouponDO, shopId, subMemberSuitableMemberVO);
        if (CanReceiveEnum.noReceiveList().contains(pfCanReceiveSuitableMemberBO.getCanReceive())) {
            return Wrapper.success(pfCanReceiveSuitableMemberBO.getCanReceive());
        }

        // 优惠券发券数量
        Integer value = couponCacheComponent.incrCouponObtainQuantity(BelongTypeEnum.PLATFORM, platformCouponDO.getId(), platformCouponDO.getQuantity());
        if (Objects.isNull(value)) {
            return Wrapper.fail(ResponseCode.MARKETING_COUPON_RECEIVE_QUANTITY_ZERO);
        }

        // 保存领取明细
        PlatformCouponDetailDO platformCouponDetailDO = new PlatformCouponDetailDO();
        platformCouponDetailDO.setCoupon(platformCouponDO);
        platformCouponDetailDO.setStatus(PlatformCouponDetailStatusEnum.RECEIVE.getCode());
        platformCouponDetailDO.setMemberId(platformCouponDO.getMemberId());
        platformCouponDetailDO.setRoleId(platformCouponDO.getRoleId());
        platformCouponDetailDO.setSubMemberId(loginUser.getMemberId());
        platformCouponDetailDO.setSubRoleId(loginUser.getMemberRoleId());
        platformCouponDetailDO.setSubMemberName(loginUser.getCompany());
        platformCouponDetailDO.setSuitableMemberType(pfCanReceiveSuitableMemberBO.getSuitableMember().getCode());
        if (PlatformCouponEffectiveTypeEnum.FIXED.getCode().equals(platformCouponDO.getEffectiveType())) {
            // 固定有效时间
            platformCouponDetailDO.setValidTimeStart(platformCouponDO.getEffectiveTimeStart());
            platformCouponDetailDO.setValidTimeEnd(platformCouponDO.getEffectiveTimeEnd());
        } else if (PlatformCouponEffectiveTypeEnum.SELF.getCode().equals(platformCouponDO.getEffectiveType())) {
            // 自领取开始, 天 -> 毫秒
            Long millisSecond = Optional.ofNullable(platformCouponDO.getInvalidDay()).map(day -> day * Constants.DAY_TO_MILLISECONDS).orElse(0L);
            platformCouponDetailDO.setValidTimeStart(System.currentTimeMillis());
            platformCouponDetailDO.setValidTimeEnd(System.currentTimeMillis() + millisSecond);
        }
        platformCouponDetailDO.setCreateTime(System.currentTimeMillis());

        // 保存数据
        platformCouponDetailRepository.saveAndFlush(platformCouponDetailDO);

        // 生成券码
        platformCouponDetailDO.setCode(couponCacheComponent.generateMerchantCouponCode(platformCouponDetailDO.getId()));
        platformCouponDetailRepository.saveAndFlush(platformCouponDetailDO);

        // 优惠券过期
        couponDetailExpireComponent.sendMqMsgCouponDetailExpire(this.createPfCouponDetailDTO(platformCouponDetailDO));

        // 是否能继续领取
        CanReceiveEnum canReceiveEnum = couponReceiveCheckRuleComponent.checkPlatformReceiveDetailComplete(loginUser, platformCouponDO);
        return Wrapper.success(canReceiveEnum);
    }

    /**
     * 领取商家优惠券
     * @param loginUser 登录用户信息
     * @param shopId 商城id
     * @param merchantCouponDO 商家优惠券
     * @return 返回结果
     */
    public Wrapper<CanReceiveEnum> receiveMerchantCoupon(UserLoginCacheDTO loginUser, Long shopId, MerchantCouponDO merchantCouponDO) {

        // 查询会员关系
        List<AtSubMemberSuitableMemberVO> subMemberSuitableMemberVOList = null;
        subMemberSuitableMemberVOList = suitableMemberInfoComponent.listAbilitySubMemberSuitableMember(loginUser.getMemberId(), loginUser.getMemberRoleId(),
                Stream.of(merchantCouponDO).map(e -> new MemberAndRoleIdBO(e.getMemberId(), e.getRoleId())).collect(Collectors.toList()));
        if (CollectionUtils.isEmpty(subMemberSuitableMemberVOList)) {
            return Wrapper.fail(ResponseCode.MARKETING_QUERY_MEMBER_RELATION);
        }

        AtCanReceiveSuitableMemberBO atCanReceiveSuitableMemberBO = couponReceiveCheckRuleComponent.baseCheckMerchantCanReceiveComplete(loginUser, merchantCouponDO, shopId, subMemberSuitableMemberVOList);
        if (CanReceiveEnum.noReceiveList().contains(atCanReceiveSuitableMemberBO.getCanReceive())) {
            return Wrapper.fail(ResponseCode.MARKETING_COUPON_RECEIVE_CONDITION);
        }

        return saveMerchantCouponBaseInfo(loginUser,shopId,merchantCouponDO,atCanReceiveSuitableMemberBO.getSuitableMember().getCode(),Boolean.FALSE);
    }

    /**
     * 赠送商家优惠券
     * @param loginUser 登录用户信息
     * @param shopId 商城id
     * @param merchantCouponDO 商家优惠券
     * @return 返回结果
     */
    public Wrapper<Void> receiveMerchantCouponByActivity(UserLoginCacheDTO loginUser, Long shopId, MerchantCouponDO merchantCouponDO,Integer quantity) {

        // 查询会员关系
        List<AtSubMemberSuitableMemberVO> subMemberSuitableMemberVOList = suitableMemberInfoComponent.listAbilitySubMemberSuitableMember(loginUser.getMemberId(), loginUser.getMemberRoleId(),
                Stream.of(merchantCouponDO).map(e -> new MemberAndRoleIdBO(e.getMemberId(), e.getRoleId())).collect(Collectors.toList()));
        if (CollectionUtils.isEmpty(subMemberSuitableMemberVOList)) {
            return Wrapper.fail(ResponseCode.MARKETING_QUERY_MEMBER_RELATION);
        }

        AtCanReceiveSuitableMemberBO atCanReceiveSuitableMemberBO = couponReceiveCheckRuleComponent.baseCheckMerchantCanReceiveCompleteByActivity(loginUser, merchantCouponDO, shopId, subMemberSuitableMemberVOList);
        if (CanReceiveEnum.noReceiveList().contains(atCanReceiveSuitableMemberBO.getCanReceive())) {
            return Wrapper.fail(ResponseCode.MARKETING_COUPON_RECEIVE_CONDITION);
        }
        //查询已发券数量
/*        Integer couponObtainQuantity = couponCacheComponent.getCouponObtainQuantity(BelongTypeEnum.MERCHANT, merchantCouponDO.getId());
        if(quantity>(NumberUtil.sub(merchantCouponDO.getQuantity(),couponObtainQuantity).intValue())){
            return Wrapper.fail(ResponseCode.MARKETING_COUPON_RECEIVE_QUANTITY_ZERO);
        }*/
        for (int i = 0; i < quantity; i++) {
            Wrapper<CanReceiveEnum> result = saveMerchantCouponBaseInfo(loginUser, shopId, merchantCouponDO, atCanReceiveSuitableMemberBO.getSuitableMember().getCode(), Boolean.TRUE);
            if(result.getCode()==ResponseCode.MARKETING_COUPON_RECEIVE_QUANTITY_ZERO.getCode()){
                log.info("优惠券剩余可发放数量不足：memberId:{},roleId:{},quantity:{},merchantCouponDOId:{}",loginUser.getMemberId(),loginUser.getMemberRoleId(),quantity,merchantCouponDO.getId());
                break;
            }
        }
        return Wrapper.success();
    }


    /**
     * 领取商家优惠券
     * @param loginUser 登录用户信息
     * @param shopId 商城id
     * @param merchantCouponDO 商家优惠券
     * @return 返回结果
     */
    public Wrapper<CanReceiveEnum> saveMerchantCouponBaseInfo(UserLoginCacheDTO loginUser, Long shopId, MerchantCouponDO merchantCouponDO,Integer suitableMemberType,Boolean ignoreCheck) {
        // 优惠券发券数量
        Integer value = couponCacheComponent.incrCouponObtainQuantity(BelongTypeEnum.MERCHANT, merchantCouponDO.getId(), merchantCouponDO.getQuantity());
        if (Objects.isNull(value)) {
            return Wrapper.fail(ResponseCode.MARKETING_COUPON_RECEIVE_QUANTITY_ZERO);
        }

        MerchantCouponDetailDO merchantCouponDetailDO = new MerchantCouponDetailDO();
        merchantCouponDetailDO.setCoupon(merchantCouponDO);
        merchantCouponDetailDO.setStatus(MerchantCouponDetailStatusEnum.RECEIVE.getCode());
        merchantCouponDetailDO.setMemberId(merchantCouponDO.getMemberId());
        merchantCouponDetailDO.setRoleId(merchantCouponDO.getRoleId());
        merchantCouponDetailDO.setSubMemberId(loginUser.getMemberId());
        merchantCouponDetailDO.setSubRoleId(loginUser.getMemberRoleId());
        merchantCouponDetailDO.setSubMemberName(loginUser.getCompany());
        merchantCouponDetailDO.setSuitableMemberType(suitableMemberType);
        if (MerchantCouponEffectiveTypeEnum.FIXED.getCode().equals(merchantCouponDO.getEffectiveType())) {
            // 固定有效时间
            merchantCouponDetailDO.setValidTimeStart(merchantCouponDO.getEffectiveTimeStart());
            merchantCouponDetailDO.setValidTimeEnd(merchantCouponDO.getEffectiveTimeEnd());
        } else if (MerchantCouponEffectiveTypeEnum.SELF.getCode().equals(merchantCouponDO.getEffectiveType())) {
            // 自领取开始, 天 -> 毫秒
            Long millisSecond = Optional.ofNullable(merchantCouponDO.getInvalidDay()).map(day -> day * Constants.DAY_TO_MILLISECONDS).orElse(0L);
            merchantCouponDetailDO.setValidTimeStart(System.currentTimeMillis());
            merchantCouponDetailDO.setValidTimeEnd(System.currentTimeMillis() + millisSecond);
        }
        merchantCouponDetailDO.setCreateTime(System.currentTimeMillis());

        // 保存数据
        merchantCouponDetailRepository.saveAndFlush(merchantCouponDetailDO);

        // 生成券码
        merchantCouponDetailDO.setCode(couponCacheComponent.generateMerchantCouponCode(merchantCouponDetailDO.getId()));
        merchantCouponDetailRepository.saveAndFlush(merchantCouponDetailDO);

        // 优惠券过期
        couponDetailExpireComponent.sendMqMsgCouponDetailExpire(this.createMcCouponDetailDTO(merchantCouponDetailDO));

        // 是否能继续领取
        CanReceiveEnum canReceiveEnum =CanReceiveEnum.CAN_RECEIVE;
        if(!ignoreCheck) {//忽略检测
            couponReceiveCheckRuleComponent.checkMerchantReceiveComplete(loginUser, merchantCouponDO);
        }
        return Wrapper.success(canReceiveEnum);
    }



    /**
     * 平台发券
     * @param platformCouponDO 平台优惠券
     * @param grantMembersReqList 给发券的会员
     * @return 返回结果
     */
    public Wrapper<Void> grantPlatformCoupon(PlatformCouponDO platformCouponDO, List<PlatformCouponGrantMemberRequest> grantMembersReqList) {
        // 基本规则校验
        Wrapper<Void> checkBaseRuleWrapper = couponReceiveCheckRuleComponent.checkPlatformAppointCouponBaseRule(platformCouponDO);
        if (ResponseCode.SUCCESS.getCode() != checkBaseRuleWrapper.getCode()) {
            return checkBaseRuleWrapper;
        }

        // 会员映射
        Map<MemberAndRoleIdBO, PlatformCouponGrantMemberRequest> grantMemberMap = Optional.ofNullable(grantMembersReqList).map(members -> members.stream()
                .collect(Collectors.toMap(m -> new MemberAndRoleIdBO(m.getSubMemberId(), m.getSubRoleId()), m -> m, (m1, m2) -> m2)))
                .orElse(new HashMap<>());

        // 发券会员请求参数
        Set<MemberAndRoleIdBO> grantMembers = grantMemberMap.keySet();
        // 已发券的会员
        Set<MemberAndRoleIdBO> detailMembers = platformCouponDetailRepository.findAllByCouponId(platformCouponDO.getId()).stream()
                .map(detail -> new MemberAndRoleIdBO(detail.getSubMemberId(), detail.getSubRoleId()))
                .collect(Collectors.toSet());
        // 取补集
        grantMembers.removeAll(detailMembers);

        // 没有需要发券的会员
        if (grantMembers.size() == 0) {
            return Wrapper.success();
        }

        // 剩余领取数量要大于0
        if (couponCacheComponent.getCouponObtainQuantity(BelongTypeEnum.PLATFORM, platformCouponDO.getId()) + detailMembers.size() > platformCouponDO.getQuantity()) {
            return Wrapper.fail(ResponseCode.MARKETING_COUPON_SURPLUS_QUANTITY_ZERO);
        }

        // 保存发放明细
        List<PlatformCouponDetailDO> platformCouponDetailDOList = new ArrayList<>();
        for (MemberAndRoleIdBO memberIdAndRoleId : grantMembers) {
            PlatformCouponGrantMemberRequest grantMember = grantMemberMap.get(memberIdAndRoleId);
            if (Objects.isNull(grantMember)) {
                continue;
            }

            // 优惠券发券数量
            Integer value = couponCacheComponent.incrCouponObtainQuantity(BelongTypeEnum.PLATFORM, platformCouponDO.getId(), platformCouponDO.getQuantity());
            if (Objects.isNull(value)) {
                continue;
            }

            PlatformCouponDetailDO platformCouponDetailDO = new PlatformCouponDetailDO();
            platformCouponDetailDO.setCoupon(platformCouponDO);
            platformCouponDetailDO.setStatus(PlatformCouponDetailStatusEnum.RECEIVE.getCode());
            platformCouponDetailDO.setMemberId(platformCouponDO.getMemberId());
            platformCouponDetailDO.setRoleId(platformCouponDO.getRoleId());
            platformCouponDetailDO.setSubMemberId(grantMember.getSubMemberId());
            platformCouponDetailDO.setSubRoleId(grantMember.getSubRoleId());
            platformCouponDetailDO.setSubMemberName(grantMember.getSubMemberName());
            platformCouponDetailDO.setSuitableMemberType(grantMember.getSuitableMemberType());
            platformCouponDetailDO.setCreateTime(System.currentTimeMillis());
            if (PlatformCouponEffectiveTypeEnum.FIXED.getCode().equals(platformCouponDO.getEffectiveType())) {
                // 固定有效时间
                platformCouponDetailDO.setValidTimeStart(platformCouponDO.getEffectiveTimeStart());
                platformCouponDetailDO.setValidTimeEnd(platformCouponDO.getEffectiveTimeEnd());
            } else if (PlatformCouponEffectiveTypeEnum.SELF.getCode().equals(platformCouponDO.getEffectiveType())) {
                // 自领取开始, 天 -> 毫秒
                Long millisSecond = Optional.ofNullable(platformCouponDO.getInvalidDay()).map(day -> day * Constants.DAY_TO_MILLISECONDS).orElse(0L);
                platformCouponDetailDO.setValidTimeStart(System.currentTimeMillis());
                platformCouponDetailDO.setValidTimeEnd(System.currentTimeMillis() + millisSecond);
            }
            platformCouponDetailDOList.add(platformCouponDetailDO);
        }
        platformCouponDetailRepository.saveAll(platformCouponDetailDOList);

        // 券码
        platformCouponDetailDOList.forEach(detail -> detail.setCode(couponCacheComponent.generatePlatformCouponCode(detail.getId())));
        platformCouponDetailRepository.saveAll(platformCouponDetailDOList);

        // 优惠券过期
        for (PlatformCouponDetailDO platformCouponDetailDO : platformCouponDetailDOList) {
            couponDetailExpireComponent.sendMqMsgCouponDetailExpire(this.createPfCouponDetailDTO(platformCouponDetailDO));
        }

        return Wrapper.success();
    }

    /**
     * 商家发券
     * @param merchantCouponDO 商家优惠券
     * @param grantMembersReqList 给发券的会员
     * @return 返回结果
     */
    public Wrapper<Void> grantMerchantCoupon(MerchantCouponDO merchantCouponDO, List<MerchantCouponGrantMemberRequest> grantMembersReqList) {
        // 基本规则校验
        Wrapper<Void> checkBaseRuleWrapper = couponReceiveCheckRuleComponent.checkMerchantAppointCouponBaseRule(merchantCouponDO);
        if (ResponseCode.SUCCESS.getCode() != checkBaseRuleWrapper.getCode()) {
            return checkBaseRuleWrapper;
        }

        // 会员映射
        Map<MemberAndRoleIdBO, MerchantCouponGrantMemberRequest> grantMemberMap = Optional.ofNullable(grantMembersReqList).map(members -> members.stream()
                .collect(Collectors.toMap(m -> new MemberAndRoleIdBO(m.getSubMemberId(), m.getSubRoleId()), m -> m, (m1, m2) -> m2)))
                .orElse(new HashMap<>());

        // 发券会员请求参数
        Set<MemberAndRoleIdBO> grantMembers = grantMemberMap.keySet();
        // 已发券的会员
        Set<MemberAndRoleIdBO> detailMembers = merchantCouponDetailRepository.findAllByCouponId(merchantCouponDO.getId()).stream()
                .map(detail -> new MemberAndRoleIdBO(detail.getSubMemberId(), detail.getSubRoleId()))
                .collect(Collectors.toSet());
        // 取补集
        grantMembers.removeAll(detailMembers);

        // 没有需要发券的会员
        if (grantMembers.size() == 0) {
            return Wrapper.success();
        }

        // 剩余领取数量要大于0
        if (couponCacheComponent.getCouponObtainQuantity(BelongTypeEnum.MERCHANT, merchantCouponDO.getId()) + detailMembers.size() > merchantCouponDO.getQuantity()) {
            return Wrapper.fail(ResponseCode.MARKETING_COUPON_SURPLUS_QUANTITY_ZERO);
        }

        // 保存发放明细
        List<MerchantCouponDetailDO> merchantCouponDetailDOList = new ArrayList<>();
        for (MemberAndRoleIdBO memberIdAndRoleId : grantMembers) {
            MerchantCouponGrantMemberRequest grantMember = grantMemberMap.get(memberIdAndRoleId);
            if (Objects.isNull(grantMember)) {
                continue;
            }

            // 优惠券发券数量
            Integer value = couponCacheComponent.incrCouponObtainQuantity(BelongTypeEnum.MERCHANT, merchantCouponDO.getId(), merchantCouponDO.getQuantity());
            if (Objects.isNull(value)) {
                return Wrapper.fail(ResponseCode.MARKETING_COUPON_RECEIVE_QUANTITY_ZERO);
            }

            MerchantCouponDetailDO merchantCouponDetailDO = new MerchantCouponDetailDO();
            merchantCouponDetailDO.setCoupon(merchantCouponDO);
            merchantCouponDetailDO.setStatus(MerchantCouponDetailStatusEnum.RECEIVE.getCode());
            merchantCouponDetailDO.setMemberId(merchantCouponDO.getMemberId());
            merchantCouponDetailDO.setRoleId(merchantCouponDO.getRoleId());
            merchantCouponDetailDO.setSubMemberId(grantMember.getSubMemberId());
            merchantCouponDetailDO.setSubRoleId(grantMember.getSubRoleId());
            merchantCouponDetailDO.setSubMemberName(grantMember.getSubMemberName());
            merchantCouponDetailDO.setSuitableMemberType(grantMember.getSuitableMemberType());
            merchantCouponDetailDO.setCreateTime(System.currentTimeMillis());
            if (MerchantCouponEffectiveTypeEnum.FIXED.getCode().equals(merchantCouponDO.getEffectiveType())) {
                // 固定有效时间
                merchantCouponDetailDO.setValidTimeStart(merchantCouponDO.getEffectiveTimeStart());
                merchantCouponDetailDO.setValidTimeEnd(merchantCouponDO.getEffectiveTimeEnd());
            } else if (MerchantCouponEffectiveTypeEnum.SELF.getCode().equals(merchantCouponDO.getEffectiveType())) {
                // 自领取开始, 天 -> 毫秒
                Long millisSecond = Optional.ofNullable(merchantCouponDO.getInvalidDay()).map(day -> day * Constants.DAY_TO_MILLISECONDS).orElse(0L);
                merchantCouponDetailDO.setValidTimeStart(System.currentTimeMillis());
                merchantCouponDetailDO.setValidTimeEnd(System.currentTimeMillis() + millisSecond);
            }
            merchantCouponDetailDOList.add(merchantCouponDetailDO);
        }
        merchantCouponDetailRepository.saveAll(merchantCouponDetailDOList);

        // 券码
        merchantCouponDetailDOList.forEach(detail -> detail.setCode(couponCacheComponent.generateMerchantCouponCode(detail.getId())));
        merchantCouponDetailRepository.saveAll(merchantCouponDetailDOList);

        // 优惠券过期
        for (MerchantCouponDetailDO merchantCouponDetailDO : merchantCouponDetailDOList) {
            couponDetailExpireComponent.sendMqMsgCouponDetailExpire(this.createMcCouponDetailDTO(merchantCouponDetailDO));
        }

        return Wrapper.success();
    }


    private CouponDetailExpireDTO createPfCouponDetailDTO(PlatformCouponDetailDO platformCouponDetailDO) {
        CouponDetailExpireDTO couponDetailExpireDTO = new CouponDetailExpireDTO();
        couponDetailExpireDTO.setCouponDetailId(platformCouponDetailDO.getId());
        couponDetailExpireDTO.setBelongType(BelongTypeEnum.PLATFORM.getCode());
        couponDetailExpireDTO.setValidTimeStart(platformCouponDetailDO.getValidTimeStart());
        couponDetailExpireDTO.setValidTimeEnd(platformCouponDetailDO.getValidTimeEnd());
        couponDetailExpireDTO.setCreateTime(platformCouponDetailDO.getCreateTime());
        return couponDetailExpireDTO;
    }

    private CouponDetailExpireDTO createMcCouponDetailDTO(MerchantCouponDetailDO merchantCouponDetailDO) {
        CouponDetailExpireDTO couponDetailExpireDTO = new CouponDetailExpireDTO();
        couponDetailExpireDTO.setCouponDetailId(merchantCouponDetailDO.getId());
        couponDetailExpireDTO.setBelongType(BelongTypeEnum.MERCHANT.getCode());
        couponDetailExpireDTO.setValidTimeStart(merchantCouponDetailDO.getValidTimeStart());
        couponDetailExpireDTO.setValidTimeEnd(merchantCouponDetailDO.getValidTimeEnd());
        couponDetailExpireDTO.setCreateTime(merchantCouponDetailDO.getCreateTime());
        return couponDetailExpireDTO;
    }
}

